﻿global using KeyCode = SFML.Window.Keyboard.Key;
global using MouseCode = SFML.Window.Mouse.Button;
using SFML.System;
using SFML.Window;

namespace WolfCarol.SFU
{
    public class Axis
    {
        public KeyCode PositiveKey { get; set; }
        public KeyCode NegativeKey { get; set; }
        public KeyCode AltPositiveKey { get; set; }
        public KeyCode AltNegativeKey { get; set; }
    }

    public static class Input
    {
        private static Dictionary<KeyCode, bool> _keyStateLastFrameDict = new Dictionary<KeyCode, bool>();

        private static Dictionary<MouseCode, bool> _mouseStateLastFrameDict = new Dictionary<MouseCode, bool>();

        private static Dictionary<string, Axis> _axisDict = new Dictionary<string, Axis>();

        static Input()
        {
            _axisDict.Add("Horizontal", new Axis()
            {
                PositiveKey = KeyCode.D,
                NegativeKey = KeyCode.A,
                AltPositiveKey = KeyCode.Right,
                AltNegativeKey = KeyCode.Left
            });
            _axisDict.Add("Vertical", new Axis()
            {
                PositiveKey = KeyCode.S,
                NegativeKey = KeyCode.W,
                AltPositiveKey = KeyCode.Down,
                AltNegativeKey = KeyCode.Up
            });
        }

        public static bool GetKeyDown(KeyCode key)
        {
            bool keyState = Keyboard.IsKeyPressed(key);

            if (keyState == false)
            {
                return false;
            }

            if (_keyStateLastFrameDict.ContainsKey(key) == false)
            {
                _keyStateLastFrameDict[key] = keyState;
                return true;
            }

            return _keyStateLastFrameDict[key] == false;
        }

        public static bool GetKeyUp(KeyCode key)
        {
            bool keyState = Keyboard.IsKeyPressed(key);

            if (keyState == true)
            {
                return false;
            }

            if (_keyStateLastFrameDict.ContainsKey(key) == false)
            {
                _keyStateLastFrameDict[key] = keyState;
                return false;
            }

            return _keyStateLastFrameDict[key] == true;
        }

        public static bool GetKey(KeyCode key)
        {
            return Keyboard.IsKeyPressed(key);
        }

        public static float GetAxis(string axisName)
        {
            if (_axisDict.ContainsKey(axisName) == false)
            {
                throw new ArgumentException("Undefined Axis.");
            }

            return ((Keyboard.IsKeyPressed(_axisDict[axisName].PositiveKey)
                || Keyboard.IsKeyPressed(_axisDict[axisName].AltPositiveKey)) ? 1f : 0f)
                + ((Keyboard.IsKeyPressed(_axisDict[axisName].NegativeKey)
                || Keyboard.IsKeyPressed(_axisDict[axisName].AltNegativeKey)) ? -1f : 0f);
        }

        public static bool GetMouseButtonDown(MouseCode mouse)
        {
            bool mouseState = Mouse.IsButtonPressed(mouse);

            if (mouseState == false)
            {
                return false;
            }

            if (_mouseStateLastFrameDict.ContainsKey(mouse) == false)
            {
                _mouseStateLastFrameDict[mouse] = mouseState;
                return true;
            }

            return _mouseStateLastFrameDict[mouse] == false;
        }

        public static bool GetMouseButtonUp(MouseCode mouse)
        {
            bool mouseState = Mouse.IsButtonPressed(mouse);

            if (mouseState == true)
            {
                return false;
            }

            if (_mouseStateLastFrameDict.ContainsKey(mouse) == false)
            {
                _mouseStateLastFrameDict[mouse] = mouseState;
                return false;
            }

            return _mouseStateLastFrameDict[mouse] == true;
        }

        public static bool GetMouseButton(MouseCode mouse)
        {
            return Mouse.IsButtonPressed(mouse);
        }

        public static Vector2i MousePosition => Mouse.GetPosition(Window.Instance.Base);

        public static void UpdateInputStates()
        {
            foreach (var key in _keyStateLastFrameDict.Keys)
            {
                _keyStateLastFrameDict[key] = Keyboard.IsKeyPressed(key);
            }

            foreach (var mouse in _mouseStateLastFrameDict.Keys)
            {
                _mouseStateLastFrameDict[mouse] = Mouse.IsButtonPressed(mouse);
            }
        }
    }
}
